package cerebrum.controller;

import cerebrum.common.*;
import cerebrum.enums.LogCode;
import cerebrum.enums.SetUpMeaages;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Random;
import java.util.concurrent.TimeUnit;

public class WallpaperCerebrum {
    private static Random random;

    static {
        try {
            random = SecureRandom.getInstanceStrong();
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
    }

    /**
     * start run
     *
     * @param isInit
     * @message: 1、先判断今天是否下载了壁纸，再判断昨天是否下载了壁纸，如果今天下载了壁纸就运行今天的壁纸，
     * 今天没有下载，就运行昨天的壁纸，昨天也没有下载，就视为首次运行，则将默认的6张图片先写入本地的用户设置的图库并运行，
     * 如此是为了避免用户觉得开启了软件也没有效果的错觉。
     * 2、今天有没有下载都会进入下载逻辑，判断下载数量，不够进入下载，下载后进行递归图片挑选，在进行下一轮的补算下载，
     * 直到合格的图片等于用户设置的数量为止
     * 3.通知原来的壁纸替换线程停止，开启新的替换线程
     */
    public static void startRun(boolean isInit) {
        try {
            //设置开机启动启动
            setPowerBoot();
            //今天是否下载了壁纸
            boolean today = FilePathUtil.todayImagesItExist();
            //昨天是否下载了图片
            boolean yesterDay = FilePathUtil.yesterDayImagesItExist();
            String imagesPath = null;
            if (today) {
                imagesPath = FilePathUtil.getToDayImagesPath();

            } else if (yesterDay) {
                imagesPath = FilePathUtil.getYesterDayImagesPath();
            } else {
                //将默认的壁纸写入存放壁纸的目录
                FirstRunImagesWrite firstRunImagesWrite = new FirstRunImagesWrite();
                firstRunImagesWrite.firstRunImagesWrite();
                imagesPath = FilePathUtil.getDefaultImagesPath();
            }
            //运行壁纸
            wallpaperStart(imagesPath);


            //数据源处理，图片下载，主要逻辑
            cerebrumMain(isInit);
            //得到上面图片下载保存的地址
            String path = FilePathUtil.getImagesPath();

            //获取缓存中替换壁纸的线程的名称
            String name = ThreadUtil.getName();
            if (EmptyChecker.notEmpty(name)) {//空就代表没有预先开启替换壁纸
                ThreadUtil.killTask();//停止
                //休眠,等待之前的壁纸线程停止,有个调用频率，让他调用时判断到状态
                Long frequency = Long.valueOf(ConfigPropertiesUtil.get("frequency"));
                TimeUnit.SECONDS.sleep((frequency / 1000) + 1);
            }

            //开始开启线程替换壁纸
            WallpaperMotion wallpaperMotion = new WallpaperMotion();
            String s = FilePathUtil.getImagesPath();
            wallpaperMotion.setImagesPath(s);
            wallpaperMotion.start();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 壁纸运行
     *
     * @param filePath
     */
    private static void wallpaperStart(String filePath) {
        WallpaperMotion wallpaperMotion = new WallpaperMotion();

        wallpaperMotion.setImagesPath(filePath);
        wallpaperMotion.start();

        String name = Thread.currentThread().getName();
        //将线程名称存到缓存器
        ThreadUtil.threadCacheInit(name, true);
    }

    /**
     * 数据源处理，图片下载，主要逻辑
     *
     * @param isInit 是否为第一次执行，初始化或者补算
     */
    public static void cerebrumMain(boolean isInit) {
        try {
            //第一次从设置面板进入使用或者是补算立即执行，以后每天都要延后用户设置的时间
            if (!isInit) {
                //读取用户设置的多久更新,延后更新是因为很多用户开机时电脑很卡和要打开很多软件，所以我们这个比较耗费网络及io的功能延后
                int updateImagesDate = Integer.valueOf(ConfigPropertiesUtil.get("updateImagesDate"));
                TimeUnit.SECONDS.sleep(updateImagesDate);
            }
            //用户设置的壁纸数量
            int userDownloadNum = Integer.valueOf(ConfigPropertiesUtil.get("downloadNum"));
            //已下载的数量
            int imagesSize = imagesDownloaded();
            if (imagesSize < userDownloadNum) {
                //得到上面图片下载保存的地址
                String path = FilePathUtil.getImagesPath();
                //读取json文件中的所有类型的图片数据源
                JSONObject imagesDataSource = FileUtil.readImagesDataSource();
                //壁纸下载
                imageDataSource(imagesDataSource);
                //休眠一分钟再执行，确保上面开多线程下载的图片都下载完成，避免图片还在下载中，挑选时误认为是下载错误的壁纸
                TimeUnit.SECONDS.sleep(60);

                //挑选按图片，将不合格的图片剔除
                imageFileEliminate(path);
                //递归判断下载的数量是否满足用户设置的数量，不满足则继续下载
                cerebrumMain(true);
            }
            //清除旧的壁纸
            cleaningImages();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }


    /**
     * 清除旧的壁纸
     */
    private static void cleaningImages() {
        //获取用户设置的多久删除一次
        Integer isCleaningImages = Integer.valueOf(ConfigPropertiesUtil.get("isCleaningImages"));
        //用户设置不删除
        if (isCleaningImages == 0) {
            return;
        }
        //往后溯用户设置的天数，如果存在这个文件夹，就删除
        LocalDate deleteTime = LocalDate.now().minusDays(isCleaningImages);
        String deleteUrl = SetUpMeaages.imagesPath.getPath() + File.separator + deleteTime;
        deleteOldImage(deleteUrl);
    }

    /**
     * 壁纸下载
     *
     * @param imagesDataSource 壁纸数据源
     * @throws IOException
     * @throws InterruptedException
     */
    public static void imageDataSource(JSONObject imagesDataSource) throws IOException, InterruptedException {

        //数据源根据用户设置消减或补齐
        List<String> dataSource = imageDataSourceChoose(imagesDataSource);

        //开始下载
        for (int i = 0; i < dataSource.size(); i++) {
            ImagesDownload.downWallPaper1(String.valueOf(dataSource.get(i)));
            //每下载一张休眠7秒，防止频繁请求被禁ip
            TimeUnit.SECONDS.sleep(7);
        }
        //将更新状态持久化到配置文件
        HashMap<String, Object> map = new HashMap<>();
        map.put("update_status", true);
        map.put("last_time_download_time", LocalDateTime.now());
        FileUtil.writeFunctionRecord(map);
    }

    /**
     * 设置开机启动
     */
    private static void setPowerBoot() throws IOException {
        //开机启动是否存在
        boolean exists = CreateShortcut.isExists(CreateShortcut.startup, CommonConst.EXENAME + ".lnk");
        if (exists) {
            return;
        }
        HashMap<String, String> hashMap = new HashMap<String, String>();

        String exeRunPath = new File("").getCanonicalPath();
        hashMap.put(CommonConst.EXENAME+".exe", CommonConst.EXENAME + ".exe");
        CreateShortcut shortcut = new CreateShortcut(exeRunPath + File.separator, hashMap);
        shortcut.createAutoStart(CreateShortcut.startup);
    }

    /**
     * 获取已下载的数量
     *
     * @return
     */
    private static int imagesDownloaded() {
        String imagesPath = FilePathUtil.getImagesPath();
        File file = new File(imagesPath);
        File[] files = file.listFiles();
        if (EmptyChecker.isEmpty(files)) {
            return 0;
        }
        return files.length;
    }

    /**
     * image Data Source Choose
     *
     * @param imagesDataSourceJson 所有类型的图片数据源
     * @return
     */
    private static List<String> imageDataSourceChoose(JSONObject imagesDataSourceJson) {
        List<String> resultDataSource = new ArrayList<>();
        String likeType = ConfigPropertiesUtil.get("likeType");
        JSONArray like = JSONArray.parseArray(likeType);
        //获取用户选择的壁纸类型
        //获取对应类型的数据源
        List<String> wallpaperType = new ArrayList<>();
        for (Object str : like) {
            List<String> o = (List<String>) imagesDataSourceJson.get(str);
            wallpaperType.addAll(o);
        }
        //已下载的数量
        int userDownloadNum = imagesDownloaded();
        //用户设置的
        int userSetUpDownloadNum = Integer.parseInt(ConfigPropertiesUtil.get("downloadNum"));
        //计算还要下载多少张
        int downloadNum = userSetUpDownloadNum - userDownloadNum;
        //数据源的数量
        int imagesSize = wallpaperType.size();
        //如果用户设置的获取数量等于于数据源量
        if (downloadNum == imagesSize) {
            return wallpaperType;
        } else if (downloadNum < imagesSize) {
            //便随机获取指定数量的的数据源
            for (int i = 0; i < downloadNum; i++) {//这里其实可以写成加权随机，有时间再修改吧
                int n = random.nextInt(wallpaperType.size());
                resultDataSource.add(wallpaperType.get(n));
                wallpaperType.remove(n);
            }
        } else if (downloadNum > imagesSize) {
            resultDataSource.addAll(wallpaperType);
            int num = downloadNum - wallpaperType.size();
            //就将其中的数据源随机取出几条加上
            for (int i = 0; i < num; i++) {

                int n = random.nextInt(wallpaperType.size());
                resultDataSource.add(wallpaperType.get(n));
            }
        }
        return resultDataSource;
    }

    /**
     * 对下载的低分辨率，下载不成功的图片淘汰清理
     *
     * @param url
     */
    private static void imageFileEliminate(String url) throws IOException {
        File images = new File(url);
        //文件路径不存在就不用删除了
        if (!images.exists()) {
            return;
        }
        //获得该文件夹下所有的文件
        File[] files = images.listFiles();

        for (File file : files) {
            if (!file.isFile()) continue;
            try {
                //读取为文件格式
                BufferedImage read = ImageIO.read(file);
                //没下载成功size为0的文件读取后为null
                if (EmptyChecker.isEmpty(read)) {
                    LogUtils.saveLog(LogCode.FAILED.getValue(), "删除", file.getPath());
                    file.delete();//删除没下载成功的
                } else {
                    //获得高
                    int height = read.getHeight();
                    //获得宽
                    int width = read.getWidth();
                    //高度大于宽1.3倍像素的删除，这种图片再壁纸中也只能显示出一部分，没法看，适合手机使用
                    if (imageCheck(height, width)) {
                        file.delete();
                    }
                }


            } catch (IOException e) {
                e.printStackTrace();
            }
        }


    }

    //删除文件及其子文件和文件夹
    private static void deleteOldImage(String url) {
        File images = new File(url);
        try {
            //文件路径不存在就不用删除了
            if (!images.exists()) {
                return;
            }
            //获得该文件夹下所有的文件
            File[] files = images.listFiles();
            //如果文件夹下啥也没有就把文件夹给删了
            if (EmptyChecker.isEmpty(files)) {
                images.delete();
            } else {
                for (File file : files) {
                    //循环删除，是文件就直接删除
                    if (file.isFile()) {
                        file.delete();
                    } else if (file.isDirectory()) { // 递归删除子目录
                        deleteOldImage(file.getAbsolutePath());
                    }
                }
            }
        } finally {
            images.delete();
        }
    }

    //高大于宽,比例大于1.30
    private static boolean imageCheck(int height, int width) {
        Double dh = Double.valueOf(height);
        Double dw = Double.valueOf(width);

        return height > width && ((dh / dw) > 1.30);
    }
}
